import $ from "jquery";
import RunLoop from "./run_loop";
import System from "./system";
import Mat3 from "./mat3";
import Vec2 from "./vec2";
import TouchEvent from "./touch_event";
import Touch from "./touch";
import TextAlign from "./text_align";

class RenderEngine {
  stage = null;
  $canvas = null;
  $body = null;
  $txtFPS = null;
  constructor(n) {
    this.stage = n;
    this.$body = $("body");
    this.$txtFPS = this.$body.find("input.txt_fps");
    this.$canvas = $("<canvas></canvas>");
    this.$body.append(this.$canvas);
    $(window).bind("resize", () => {
      this.stage.needResizeFlag = !0;
    });
    this.resize();
    this.configEvents();
    RunLoop.addToRunLoop(Mat3);
  }
  onActivate() {
    this.stage.active(!0);
  }
  onDeactivate() {
    this.stage.active(!1);
  }
  resize() {
    let n = $(window).width(),
      r = $(window).height();
      this.$body.width(n).height(r),
      this.$canvas.css("position", "absolute"),
      this.$canvas.css("left", 0),
      this.$canvas.css("top", 0),
      this.$canvas.css("width", n),
      this.$canvas.css("height", r),
      this.stage.resize(n, r);
  }
  fire(e, t) {
    this.$txtFPS != null && this.$txtFPS.val(Math.round((1 / t) * 10) / 10),
    this.stage.update(e, t);
    if (this.stage.needToRender() || this.stage.needResizeFlag) {
      this.stage.needToRender(!1),
      this.stage.needResizeFlag && ((this.stage.needResizeFlag = !1), this.resize()),
      this.$canvas.attr("width", this.stage.stageWidth()),
      this.$canvas.attr("height", this.stage.stageHeight());
      let r = this.$canvas[0].getContext("2d");
      r.clearRect(0, 0, this.stage.stageWidth(), this.stage.stageHeight()),
      this.render(r, this.stage, this.stage.stageMatrix());
    }
  }
  takePhoto(t, n, i) {
    let o: any = $("<canvas></canvas>");
    o.attr("width", t.width()), o.attr("height", t.height());
    let u = t.clone();
    u.matrix(new Mat3());
    let a = o[0].getContext("2d");
    this.render(a, u, new Mat3(), 1);
    let f = o[0].toDataURL(typeof i == "string" ? i : "image/png"),
      l = $("<img/>");
    l.load(function () {
      Boolean(n) && n(t, l[0]);
    }),
      l.attr("src", f);
  }
  render(e, t, n, i?) {
    let s = this;
    (n = n instanceof Object ? n : new Mat3()),
      (i = isNaN(i) === !1 ? i : 1),
      (n = t.matrix().concatWith(n)),
      (i *= t.alpha());
    let o = i <= 0 || (t.mask() != null && t.mask().commands().length <= 0);
    if (o === !1) {
      (e.globalAlpha = i), e.setTransform(n.a, n.b, n.c, n.d, n.tx, n.ty);
      if (t.cachedImage != null)
        e.drawImage(t.cachedImage, 0, 0, t.width(), t.height());
      else {
        t.clip() &&
          (e.save(),
          e.beginPath(),
          e.rect(0, 0, t.width(), t.height()),
          e.clip()),
          t.mask() != null && (e.save(), s.drawPaths(e, t.mask()), e.clip()),
          t.shadowColor() != null &&
            (e.save(),
            (e.shadowOffsetX = t.shadowOffsetX()),
            (e.shadowOffsetY = t.shadowOffsetY()),
            (e.shadowBlur = t.shadowBlur()),
            (e.shadowColor = t.shadowColor().toRGBAString()));
        if (t.bgColor() != null && t.bgColor().a() > 0) {
          e.beginPath();
          let u = t.rect(t);
          e.rect(u.x, u.y, u.width, u.height),
            (e.globalAlpha = i * (t.bgColor().a() / 255));
          let a = t.bgColor().clone();
          a.adjustSaturation(t.saturation()),
            (e.fillStyle = a.to24BitString()),
            e.fill();
        }
        let f = t.className;
        switch (f) {
          case "AXEStage":
          case "AXEViewContainer":
            s.renderContainer(e, t, n, i);
            break;
          case "AXEBitmap":
            s.renderBitmap(e, t);
            break;
          case "AXEMovie":
            s.renderMovie(e, t);
            break;
          case "AXEShape":
            s.renderShape(e, t, i);
            break;
          case "AXEText":
            s.renderText(e, t, i);
            break;
          default:
        }
        t.shadowColor() != null && e.restore(),
          t.mask() != null && e.restore(),
          (t.clip() || t.shadowColor() != null) && e.restore();
      }
    }
  }
  renderContainer(e, t, n, r) {
    let i = this,
      s = t.visibleSubViews();
    for (let o = 0; o < s.length; o++) {
      let u = s[o];
      i.render(e, u, n, r);
    }
  }
  renderBitmap(e, t) {
    let n = t.bitmap();
    if (n != null) {
      let r = t.width(),
        i = t.height();
      e.drawImage(n, 0, 0, n.naturalWidth, n.naturalHeight, 0, 0, r, i);
    }
  }
  renderMovie(e, t) {
    if (t.framesCount() > 0) {
      let n = t.frames()[t.currentFrame()];
      if (n != null) {
        let r = t.width(),
          i = t.height();
        e.drawImage(n, 0, 0, n.naturalWidth, n.naturalHeight, 0, 0, r, i);
      }
    }
  }
  renderShape(e, t, n) {
    let r = this;
    r.drawPaths(e, t.paths()),
      t.fillColor() != null &&
        ((e.globalAlpha = n * (t.fillColor().a() / 255)),
        (e.fillStyle = t.fillColor().to24BitString()),
        e.fill()),
      t.strokeColor() != null &&
        t.strokeSize() > 0 &&
        ((e.globalAlpha = n * (t.strokeColor().a() / 255)),
        (e.lineWidth = t.strokeSize()),
        (e.strokeStyle = t.strokeColor().to24BitString()),
        e.stroke());
  }
  renderText(e, t, n) {
    let r = this;
    t.color() != null &&
      t.text().length > 0 &&
      ((e.globalAlpha = n * (t.color().a() / 255)),
      (e.fillStyle = t.color().to24BitString()),
      (e.font = t.textStyle()),
      t.wordWrap()
        ? r.renderMultipleLineText(e, t)
        : r.renderSingleLineText(e, t));
  }
  renderMultipleLineText(e, t) {
    let n = t.text();
    if (n.length > 0 && t.width() > 0) {
      n = n.replace(/\<br\/\>/gi, "\n");
      let r = [],
        i = n.split(""),
        s = "";
      while (i.length > 0) {
        let o = i.shift();
        if (o == "\n") r.push(s), (s = "");
        else {
          s += o;
          let a = e.measureText(s).width;
          if (a > t.width() || i.length <= 0)
            a > t.width() && ((s = s.slice(0, s.length - 1)), i.unshift(o)),
              r.push(s),
              (s = "");
        }
      }
      if (t.mergeLastLine() > 0)
        for (let f = r.length - 1; f > 0; f--)
          r[f].length <= t.mergeLastLine() &&
            ((r[f - 1] += r[f]), r.splice(f, 1));
      e.textBaseline = "alphabetic";
      let l = t.lineHeight() / 2;
      for (let c = 0; c < r.length; c++) {
        let h = r[c],
          p = e.measureText(h),
          d = 0;
        t.textAlign() == TextAlign.LEFT
          ? (d = 0)
          : t.textAlign() == TextAlign.CENTER
          ? (d = t.width() / 2 - p.width / 2)
          : t.textAlign() == TextAlign.RIGHT && (d = t.width() - p.width),
          e.fillText(h, d, l),
          (l += t.lineHeight());
      }
    }
  }
  renderSingleLineText(e, t) {
    e.textBaseline = t.textVAlign();
    let n = e.measureText(t.text()),
      r = 0;
    t.textAlign() == TextAlign.LEFT
      ? (r = 0)
      : t.textAlign() == TextAlign.CENTER
      ? (r = t.width() / 2 - n.width / 2)
      : t.textAlign() == TextAlign.RIGHT && (r = t.width() - n.width),
      e.fillText(t.text(), r, t.height() / 2);
  }
  drawPaths(e, t) {
    let n = t.commands();
    e.beginPath();
    for (let r = 0; r < n.length; r++) {
      let i = n[r],
        s = i.o,
        o = i.p;
      e[s].apply(e, o);
    }
  }
  createTouchEvent(e) {
    let t = this,
      n = [];
    for (let r = 0; r < e.length; r++) {
      let s = new Vec2(e[r].pageX * t.stage.ratio(), e[r].pageY * t.stage.ratio());
      s = t.stage.stageMatrix().inversePoint(s);
      let u = new Touch(s.x, s.y, s.x, s.y);
      n.push(u);
    }
    return n;
  }
  configEvents() {
    let e = this;
    e.$canvas.bind(System.isTouchDevice() ? "touchstart" : "mousedown", function (
      t
    ) {
      let r = function (t) {
        let r = null;
        t.type == "touchstart" || t.type == "mousedown"
          ? (r = TouchEvent.TOUCH_START)
          : (r = TouchEvent.TOUCH_MOVE);
        let i = null;
        System.isTouchDevice() ? (i = t.originalEvent.touches) : (i = [t]);
        let o = e.createTouchEvent(i),
          u = new TouchEvent(e.stage, r, o);
        e.stage.triggerEvent(u), t.preventDefault();
      };
      r(t),
        e.$canvas.unbind("touchmove touchend mousemove mouseup"),
        e.$canvas.bind(System.isTouchDevice() ? "touchmove" : "mousemove", r),
        e.$canvas.bind(System.isTouchDevice() ? "touchend" : "mouseup", function () {
          let t = new TouchEvent(e.stage, TouchEvent.TOUCH_END, []);
          e.stage.triggerEvent(t),
            e.$canvas.unbind("touchmove touchend mousemove mouseup");
        });
    });
  }
}

export default RenderEngine;
